/*
 * Copyright (c) 2007 jNetX.
 * http://www.jnetx.com
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * jNetX. You shall not disclose such Confidential Information and
 * shall use it only in accordance with the terms of the license
 * agreement you entered into with jNetX.
 *
 * $Id$
 */
package com.jnetx.javax.sip;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.sip.SipStack;
import javax.sip.address.Router;
import java.lang.reflect.Constructor;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;

/**
 * @author <a href="mailto:dparhonin@jnetx.ru">Dmitry Parhonin</a>
 * @version $Revision$
 */
public class SipStackPropertyConfigurator {
    private static final Log log = LogFactory.getLog(SipStackPropertyConfigurator.class);
    private final SipStackImpl sipStack;

    SipStackPropertyConfigurator(SipStackImpl sipStack) {
        this.sipStack = sipStack;
    }

    public SipStackConfig createConfig(Properties props) {
        SipStackConfig config = new SipStackConfig();
        parseName(props.getProperty("javax.sip.STACK_NAME", "jNetX SIP Stack v1.0"), config);
        parseIPAddress(props.getProperty("javax.sip.IP_ADDRESS", null), config);
        parseOutboundProxy(props.getProperty("javax.sip.OUTBOUND_PROXY", null), config);
        parseRouterPath(props.getProperty("javax.sip.ROUTER_PATH", null), config);
        parseExtensionMethods(props.getProperty("javax.sip.EXTENSION_METHODS", null), config);
        parseAutomaticDialogSupport(props.getProperty("javax.sip.AUTOMATIC_DIALOG_SUPPORT", null), config);
        parseForkableEvents(props.getProperty("javax.sip.FORKABLE_EVENTS", null), config);
        parseUseRouterForAllURIs(props.getProperty("javax.sip.USE_ROUTER_FOR_ALL_URIS", null), config);
        return config;
    }

    private void parseName(String name, SipStackConfig config) {
        config.setName(name);
    }

    private void parseIPAddress(String ipAddress, SipStackConfig config) {
        if (ipAddress != null && !ipAddress.equals("")) {
            try {
                InetAddress inetAddress = InetAddress.getByName(ipAddress);
                config.setIpAddress(ipAddress);
            } catch (UnknownHostException e) {
                log.error("The provided IP address is wrong!", e);
            }
        }
    }

    private void parseOutboundProxy(String outboundProxy, SipStackConfig config) {
        config.setOutboundProxy(outboundProxy);
        if (outboundProxy != null) {
            //Setting defaults
            config.setOutboundProxyPort(5060);
            config.setOutboundProxyTransport("UDP");
            int colonIndex = outboundProxy.indexOf(':');
            if (colonIndex != -1) {
                config.setOutboundProxyAddress(outboundProxy.substring(0, colonIndex));
                int slashIndex = outboundProxy.indexOf('/', colonIndex);
                if (slashIndex != -1) {
                    int port = Integer.parseInt(outboundProxy.substring(colonIndex + 1, slashIndex));
                    if (port <= 0 || port >= 65535) {
                        log.warn("Wrong port of outbound proxy! Using default: " + config.getOutboundProxyPort());
                    } else {
                        config.setOutboundProxyPort(port);
                    }
                    String transport = outboundProxy.substring(slashIndex + 1);
                    if (transport == null || transport.equals("") || (!transport.equalsIgnoreCase("UDP") && !transport.equalsIgnoreCase("TCP"))) {
                        log.warn("Wrong transport for ountbound proxy! Using default: " + config.getOutboundProxyTransport());
                    } else {
                        config.setOutboundProxyTransport(transport);
                    }
                }
            }
        }
    }

    private void parseRouterPath(String routerPath, SipStackConfig config) {
        if (routerPath != null) {
            Class<? extends Router> routerClazz;
            try {
                Class<?> clazz = Class.forName(routerPath);
                routerClazz = clazz.asSubclass(Router.class);
            } catch (Exception e) {
                log.error("Cannot get the router class: " + routerPath, e);
                return;
            }
            Constructor<? extends Router> constructor;
            try {
                constructor = routerClazz.getConstructor(new Class[]{SipStack.class, String.class});
            } catch (NoSuchMethodException e) {
                log.error("Cannot get a constructor for the specified router class!", e);
                return;
            }
            try {
                sipStack.setRouter(constructor.newInstance(sipStack, config.getOutboundProxy()));
            } catch (Exception e) {
                log.error("", e);
            }
        }
    }

    private void parseExtensionMethods(String extensionMethods, SipStackConfig config) {
        if (extensionMethods != null) {
            Set<String> extensionMethodSet = config.getExtensionMethods();
            final StringTokenizer tokener = new StringTokenizer(extensionMethods, ":", false);
            while (tokener.hasMoreTokens())
                extensionMethodSet.add(tokener.nextToken());
        }
    }

    private void parseAutomaticDialogSupport(String automaticDialogSupport, SipStackConfig config) {
        if (automaticDialogSupport != null)
            config.setAutomaticDialogSupport(!automaticDialogSupport.equalsIgnoreCase("OFF"));
    }

    private void parseForkableEvents(String forkableEvents, SipStackConfig config) {
        //todo Implements this
    }

    private void parseUseRouterForAllURIs(String useRouterForAllURIs, SipStackConfig config) {
        //todo Implement this
    }
}
/*
 * $Log$
 */